﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Media;
using System.Diagnostics;
using LogFileScanner.Properties;

using WeifenLuo.WinFormsUI.Docking;

namespace LogFileScanner
{
    public partial class ProcessViewer : DockContent, LogFileScanner.Viewer
    {
        private IList<Process> processes = new List<Process>();

        public ProcessViewer()
        {
            InitializeComponent();
        }

        #region Public Interface

        public delegate void ProcessStarted(Process process);
        public delegate void ProcessFinished(Process process);

        public event Utility.VoidMethodDelegate NotifyProgressStart;
        public event Utility.VoidMethodDelegate NotifyProgressStop;
        public event Utility.MessageMethodDelegate NotifyLogMessage;

        public void Terminate()
        {
        }

        public void AddProcess(Process process)
        {
            if (InvokeRequired) { Invoke((ProcessViewer.ProcessStarted)AddProcess, process); return; }

            ListViewItem item = new ListViewItem(process.StartInfo.FileName);
            item.SubItems.Add(process.StartInfo.Arguments);
            item.SubItems.Add("Running");
            item.Tag = process;

            listProcesses.Items.Add(item);
            listProcesses.Groups[0].Items.Add(item);
        }

        public void RemoveProcess(Process process)
        {
            if (InvokeRequired) { Invoke((ProcessViewer.ProcessFinished)RemoveProcess, process); return; }

            foreach (ListViewItem item in listProcesses.Items)
            {
                if (item.Tag == process)
                {
                    item.SubItems[2].Text = "Terminated";
                    listProcesses.Groups[0].Items.Remove(item);
                    listProcesses.Groups[1].Items.Add(item);
                    return;
                }
            }
        }

        public void RegisterManaged(Managed managed)
        {
            managed.NotifyProcessStarted += new ProcessViewer.ProcessStarted(processManaged_NotifyProcessStarted);
            managed.NotifyProcessFinished += new ProcessViewer.ProcessFinished(processManaged_NotifyProcessFinished);
        }

        public void UnregisterManaged(Managed managed)
        {
            managed.NotifyProcessStarted -= processManaged_NotifyProcessStarted;
            managed.NotifyProcessFinished -= processManaged_NotifyProcessFinished;
        }
        
        #endregion

        #region Event Callback

        private void processStart()
        {
            if (NotifyProgressStart != null)
            {
                NotifyProgressStart();
            }
        }

        private void processStop()
        {
            if (NotifyProgressStop != null)
            {
                NotifyProgressStop();
            }
        }


        private void logMessage(string value, Utility.MessageLevel level)
        {
            if (NotifyLogMessage != null)
            {
                NotifyLogMessage(value, level);
            }
        }

        #endregion 

        #region Helper Methods

        void processManaged_NotifyProcessStarted(Process process)
        {
            AddProcess(process);
        }

        void processManaged_NotifyProcessFinished(Process process)
        {
            RemoveProcess(process);
        }

        private bool KillProcess(Process process)
        {
            string processName = "[unknown]";
            try
            {
                processName = process.ProcessName;

                logMessage(string.Format("Killing process: {0} at user's request", processName), Utility.MessageLevel.INFO);

                if (!process.HasExited)
                {
                    process.Kill();
                }

                return process.HasExited;
            }
            catch (InvalidOperationException ex)
            {
                if (ex.Message == "No process is associated with this object.")
                {
                    return true;
                }
                else
                {
                    logMessage(string.Format("Unable to kill the {0} process due to {1}", processName, ex.Message), Utility.MessageLevel.WARN);
                    return false;
                }
            }
            catch (Exception ex)
            {
                logMessage(string.Format("Unable to kill the {0} process due to {1}", processName, ex.Message), Utility.MessageLevel.ERROR);
                return true;
            }
            finally
            {
                RemoveProcess(process);
            }
        }

        #endregion

        #region UI Event

        private void StreamList_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.Hide();
        }

        private void buttonKill_Click(object sender, EventArgs e)
        {
            if (listProcesses.SelectedItems.Count > 0)
            {
                foreach (ListViewItem listItem in listProcesses.SelectedItems)
                {
                    Process process = listItem.Tag as Process;
                    if (process != null)
                    {
                        bool exited = KillProcess(process);
                        listItem.SubItems[2].Text = "Killed";
                    }
                }
            }
        }
              

        private void listProcesses_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listProcesses.Items.Count > 0)
            {
                buttonKill.Enabled = true;
            }
            else
            {
                buttonKill.Enabled = false;
            }

            foreach (ListViewItem item in listProcesses.SelectedItems)
            {
                Process process = item.Tag as Process;

                labelCommand.Text = process.StartInfo.FileName;
                labelArguments.Text = process.StartInfo.Arguments;

                try
                {
                    labelName.Text = process.ProcessName;
                }
                catch (Exception ex)
                {
                    if (ex.Message == "No process is associated with this object.")
                    {
                        labelName.Text = "[Process Handle Closed]";
                    }
                    else
                    {
                        labelName.Text = "[Unknown]";
                    }
                }

                try
                {
                    labelResponding.Text = process.Responding ? "Responding" : "Not Responding";
                }
                catch (Exception ex)
                {
                    if (ex.Message == "No process is associated with this object.")
                    {
                        labelResponding.Text = "[Process Handle Closed]";
                    }
                    else
                    {
                        labelResponding.Text = "[Unknown]";
                    }
                }

                try 
                {
                    labelTerminated.Text = process.HasExited ? "Terminated" : "Not Terminated";
                }
                catch (Exception ex)
                {
                    if (ex.Message == "No process is associated with this object.")
                    {
                        labelTerminated.Text = "[Process Handle Closed]";
                    }
                    else
                    {
                        labelTerminated.Text = "[Unknown]";
                    }
                }

                return;
            }
        }

        private void buttonClearTerminated_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in listProcesses.SelectedItems)
            {
                Process process = item.Tag as Process;

                bool canClose = false;

                try
                {
                    canClose = process.HasExited;
                }
                catch (InvalidOperationException ex)
                {
                    if (ex.Message == "No process is associated with this object.")
                    {
                        canClose = true;
                    }
                    else
                    {
                        logMessage(string.Format("Unable to cloase the process due to {0}", ex.Message), Utility.MessageLevel.ERROR);
                    }
                }

                if (canClose)
                {
                    listProcesses.Items.Remove(item);
                }
            }
        }

        #endregion


    }

}
